/*
    Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "GameLevelScene.h"

#include <algorithm>

#include "../MainPlayer.h"
#include "../Event.h"
#include "../Monster.h"
#include "../MonsterState.h"
#include "../ui/GameOverWidget.h"
#include "../Game.h"

#define random(x) (rand() % x)

const std::string MonsterUpdateState = "{36BB7FCF-3AE1-47FB-8105-91E1395DA4E9}";

GameLevelScene::GameLevelScene()
    : m_keyboardListenerId(-1), m_isDebug(false), m_scheduleKey("{79FB2FE8-6D60-4581-A042-80B6B07B9F6A}")
{
    m_keyState = {false};
    m_isChangeKeyState = false;
}

GameLevelScene::~GameLevelScene()
{
}

void GameLevelScene::updateKeyState()
{
    bool isStand = true;

    //移动相关的

    if (m_keyState[W] || m_keyState[A] || m_keyState[S] || m_keyState[D])
    {
        if (m_keyState[W])
        {
            m_mainRelo->move(IPlayer::Direction::Up);
        }

        if (m_keyState[A])
        {
            m_mainRelo->move(IPlayer::Direction::Left);
        }

        if (m_keyState[S])
        {
            m_mainRelo->move(IPlayer::Direction::Down);
        }

        if (m_keyState[D])
        {
            m_mainRelo->move(IPlayer::Direction::Right);
        }

        isStand = false;
    }

    //技能相关的
    if (m_keyState[K] || m_keyState[L])
    {
        int skill_id = 1;
        if (m_keyState[K])
        {
            skill_id = 2;
        }

        m_mainRelo->useSkill(skill_id);

        isStand = false;
    }

    if (isStand)
    {
        m_mainRelo->stand();
    }

    m_isChangeKeyState = false;

    return;
}

Vector2 GameLevelScene::getMainPlayerPosition()
{
    return m_mainRelo->getPosition();
}

int GameLevelScene::getMainPLayerHp()
{
    return m_mainRelo->getCurrentHp();
}

Rect GameLevelScene::getMainPlayerRect()
{
    return m_mainRelo->getRect();
}

IPlayer *GameLevelScene::getMainPlayer()
{
    return m_mainRelo.get();
}

int GameLevelScene::allocateRectId()
{
    static int i = 0;
    int id = ++i;
    m_roleRectArr.push_back(RoleRect{id, Rect::Zero});
    return id;
}

void GameLevelScene::modifyRectById(int id, const Rect &rect)
{
    for (auto &v : m_roleRectArr)
    {
        if (v.id == id)
        {
            v.rect = rect;
        }
    }
}

void GameLevelScene::freeRect(int id)
{
    auto i = std::remove_if(m_roleRectArr.begin(), m_roleRectArr.end(), [id](const RoleRect &r)
                            { return r.id == id; });
    m_roleRectArr.erase(i, m_roleRectArr.end());
}

bool GameLevelScene::isCollision(int id, const Rect &rect) const
{
    for (auto &p : m_vectorRoles)
    {
        if (p->getId() != id)
        {
            if (!p->isDeath() && p->getRect().intersectsWithRect(rect))
            {
                return true;
            }
        }
    }

    return false;
}

bool GameLevelScene::isIntersect(int self_id, const Line &self_line, int *intersect_id) const
{
    *intersect_id = -1;

    for (auto &p : m_vectorRoles)
    {
        if (p->getId() != self_id && !p->isDeath())
        {
            if (p->getRect().intersectWithLine(self_line))
            {
                *intersect_id = p->getId();
                return true;
            }
        }
    }

    return false;
}

bool GameLevelScene::init()
{
    if (!Scene::init())
    {
        return false;
    }

    auto game = GameWorld::getInstance();

    //设置地图背景
    auto bg_sf = game->getDefultSpriteFrameCache()->getSpriteFrame(L"background");
    m_mapBg = Sprite::create(bg_sf, this);
    auto size = game->getAppView()->getViewSize();
    m_mapBg->setPosition(size.width / 2, size.height / 2);

    if (!this->initGameRole())
    {
        return false;
    }

    if (!this->initGameUi())
    {
        return false;
    }

    if (!this->initInputListener())
    {
        return false;
    }

    if (!this->initEventListener())
    {
        return false;
    }

    return true;
}

void GameLevelScene::enterScene()
{
    auto game = GameWorld::getInstance();

    //设置每帧的回掉
    game->getScheduler()->addSchedulerPerFrame(std::bind(&GameLevelScene::run, this, std::placeholders::_1), m_scheduleKey);

    //开启任务 运行怪物的状态机
    game->getScheduler()->addSchedulerTaskForever([this]()
                                                  {
                                                      for (auto &m : m_monsterList)
                                                      {
                                                          m->getMonsterMachine()->loop();
                                                      } },
                                                  MonsterUpdateState, 1000 * 1);

    m_banRect = Rect(0, 500, 1280, 200);
    int id = this->allocateRectId();
    this->modifyRectById(id, m_banRect);

    game->getScheduler()->addSchedulerTaskDelay([this]()
                                                { Game::getInstance()->playAudio(Game::AudioType::BG_AUDIO); },
                                                "{39C50D61-3009-4E35-8EE2-2E381063C387}", 1000);

    return;
}

void GameLevelScene::quitScene()
{
    GameWorld::getInstance()->getScheduler()->removeSchedulerPeerFrame(m_scheduleKey);
    GameWorld::getInstance()->getEventManager()->removeListener(m_skillComplateHandle);
    GameWorld::getInstance()->getEventManager()->removeListener(m_hpchangeHandle);
    Game::getInstance()->stopAudio(Game::AudioType::BG_AUDIO);
}

bool GameLevelScene::initGameRole()
{
    m_mainRelo = std::make_unique<MainPlayer>();
    m_mainRelo->setId(this->allocateRectId());
    m_mainRelo->setGameScene(this);
    if (!m_mainRelo->init(this))
    {
        return false;
    }

    m_vectorRoles.push_back(m_mainRelo.get());

    auto levelInfo = Game::getInstance()->getCurrentLevelInfo();

    //创建怪物
    auto createMonster = [this](Monster::MonsterType type, int num)
    {
        for (int i = 0; i < num; i++)
        {
            std::shared_ptr<Monster> p = std::make_shared<Monster>();
            if (p && p->init(type, this, this))
            {
                p->setGameScene(this);

                m_monsterList.push_back(std::dynamic_pointer_cast<IMonster>(p));
                m_vectorRoles.push_back(p.get());
            }
        }
    };

    createMonster(Monster::MonsterType::MonsterTypeA, levelInfo->getMonsterACount());
    createMonster(Monster::MonsterType::MonsterTypeB, levelInfo->getMonsterBCount());
    createMonster(Monster::MonsterType::MosterTypeBoos, levelInfo->getMonsterBoosCount());

    return true;
}

bool GameLevelScene::initGameUi()
{
    auto cache = GameWorld::getInstance()->getDefultSpriteFrameCache();

    m_mainHpProgressbar = ProgressBar::create();
    m_mainHpProgressbar->move(50, 550);
    m_mainHpProgressbar->resize(Size(300, 60));
    m_mainHpProgressbar->setBackgroundImage(
        std::unique_ptr<Scale9Image>(
            Scale9Image::create(cache->getSpriteFrame(L"player-progress-bg"), Rect::Zero)));
    auto sf = cache->getSpriteFrame(L"player-progress-fill");
    auto rect = sf->getRect();
    Vector2 d(10, 10);
    m_mainHpProgressbar->setFillImage(std::unique_ptr<Scale9Image>(Scale9Image::create(sf, Rect(2, 2, rect.getWidth() - 4, rect.getHeight() - 4))));
    m_mainHpProgressbar->setPadding(15, 18, 15, 18);
    m_mainHpProgressbar->setMaxValue(m_mainRelo->getMaxHp());
    m_mainHpProgressbar->setCurrentValue(m_mainRelo->getCurrentHp());

    m_debugCheckbox = CheckBox::create();
    auto checkbox_sf_normal = cache->getSpriteFrame(L"check_nomal");
    auto chexkbox_sf_hover = cache->getSpriteFrame(L"checkbox_hover");
    auto checkbox_sf_checked = cache->getSpriteFrame(L"fill");

    m_debugCheckbox->setNormalImage(Scale9Image::createUniquePtr(checkbox_sf_normal, Rect::Zero));
    m_debugCheckbox->setHoveringImage(Scale9Image::createUniquePtr(chexkbox_sf_hover, Rect::Zero));
    m_debugCheckbox->setCheckedFillImage(Scale9Image::createUniquePtr(checkbox_sf_checked, Rect::Zero), Rect(10, 12, 25, 25));
    m_debugCheckbox->setTextRect(Rect(70, 0, 120, 50));
    m_debugCheckbox->setPosition(Vector2(400, 550));
    m_debugCheckbox->resize(Size(180, 50));
    m_debugCheckbox->setTextColor(Color4f::YellowGreen);
    m_debugCheckbox->setTextColor(Color4f::Yellow, Widget::WidgetState::Hover);
    m_debugCheckbox->setTextColor(Color4f::Red, Widget::WidgetState::Pressed);
    Font f(L"宋体", 21, Font::FONT_WEIGHT::FONT_WEIGHT_BOLD);
    m_debugCheckbox->setText(L"是否显示检测框");
    m_debugCheckbox->setFont(f);
    m_debugCheckbox->setFont(f, Widget::WidgetState::Hover);
    m_debugCheckbox->setFont(f, Widget::WidgetState::Pressed);

    m_debugCheckbox->setChangeStateListener([this](CheckBox::CheckState curr_state)
                                            {
                                                if (curr_state == CheckBox::CheckState::Checked)
                                                {
                                                    m_isDebug = true;
                                                }
                                                else
                                                {
                                                    m_isDebug = false;
                                                }

                                                auto e = std::make_shared<DebugEvent>();
                                                e->setDebug(m_isDebug);
                                                EventManager::getInstance()->triggerEvent(e, EventManager::TriggerMode::queue); });

    m_debugCheckbox->setCheckState(CheckBox::CheckState::Unchecked);

    m_currentLevel = Label::create();
    m_currentLevel->setPosition(Vector2(800, 550));
    m_currentLevel->setText(std::wstring(L"当前关卡：") + std::to_wstring(Game::getInstance()->getCurrentLevelInfo()->getLevel()));
    m_currentLevel->setTextColor(Color4f::OrangeRed);
    m_currentLevel->setFont(f);

    m_gameOverWidget = GameOverWidget::create();
    m_gameOverWidget->move(320, 200);
    m_gameOverWidget->setBackgroundImage(cache->getSpriteFrame(L"pause-bg"));
    m_gameOverWidget->hide();

    return true;
}

bool GameLevelScene::initInputListener()
{
    auto handler = EventListenerKeyboard::create();

    handler->onKeyDown = [this](EventKey *e)
    {
        switch (e->getKey())
        {
        case 'W':
            this->pressKey(W);
            break;
        case 'A':
            this->pressKey(A);
            break;
        case 'S':
            this->pressKey(S);
            break;
        case 'D':
            this->pressKey(D);
            break;
        case 'K':
            this->pressKey(K);
            break;
        case 'L':
            this->pressKey(L);
            break;
        default:
            break;
        }
    };

    handler->onKeyUp = [this](EventKey *e)
    {
        switch (e->getKey())
        {
        case 'W':
            this->releaseKey(W);
            break;
        case 'A':
            this->releaseKey(A);
            break;
        case 'S':
            this->releaseKey(S);
            break;
        case 'D':
            this->releaseKey(D);
            break;
        case 'K':
            this->releaseKey(K);
            break;
        case 'L':
            this->releaseKey(L);
            break;
        default:
            break;
        }
    };

    m_keyboardListenerId = InputEventDispatcher::getInstance()->addListener(this, handler);

    return true;
}

bool GameLevelScene::initEventListener()
{
    auto game = GameWorld::getInstance();

    //监听技能释放放毕
    m_skillComplateHandle = game->getEventManager()->addListener<SkillComplateEvent>(
        std::bind(&GameLevelScene::onMainPlayerSkillComplate, this, std::placeholders::_1));

    //监听血量变化
    m_hpchangeHandle = game->getEventManager()->addListener<MainPlayerHpChangeEvent>(
        std::bind(&GameLevelScene::onMainPlayerHpChange, this, std::placeholders::_1));

    return true;
}

void GameLevelScene::run(float dt)
{
    //先处理按键逻辑
    if (m_isChangeKeyState)
    {
        this->updateKeyState();
    }

    //让后运行角色的逻辑
    m_mainRelo->run(dt);

    //运行怪物的逻辑
    for (auto &m : m_monsterList)
    {
        m->run(dt);
    }

    //对角色进行排序
    std::sort(m_vectorRoles.begin(), m_vectorRoles.end(), [](IPlayer *p1, IPlayer *p2)
              { return p1->getPosition().y > p2->getPosition().y; });

    int i = 0;
    for (auto &p : m_vectorRoles)
    {
        p->setOrder(i);
        i++;
    }

    //判断是否都死亡了
    for (auto &m : m_monsterList)
    {
        if (!m->isDeath())
        {
            return;
        }
    }

    this->onGameOver();

    if (Game::getInstance()->getCurrentGameLevel() == MAX_LEAVEL)
    {
        this->onGameVictory();
    }
    else
    {
        this->onNextLevel();
    }

    return;
}

IPlayer *GameLevelScene::findPlayerById(int id)
{
    for (auto &v : m_vectorRoles)
    {
        if (v->getId() == id)
        {
            return v;
        }
    }

    return nullptr;
}

void GameLevelScene::pressKey(KeyIndex index)
{
    m_isChangeKeyState = true;
    m_keyState[index] = true;
}

void GameLevelScene::releaseKey(KeyIndex index)
{
    m_isChangeKeyState = true;
    m_keyState[index] = false;
}

void GameLevelScene::draw(IRender *render, const Matrix4X4 &transform)
{
    //画出禁区
    if (m_isDebug)
    {
        Geometry::drawRect(render, m_banRect, Color4f::Red);
    }
}

void GameLevelScene::onMainPlayerHpChange(Event *e)
{
    MainPlayerHpChangeEvent *event = dynamic_cast<MainPlayerHpChangeEvent *>(e);
    if (event)
    {
        m_mainHpProgressbar->setCurrentValue(event->getCurrentHp());
        //如果玩家死亡
        if (event->getCurrentHp() <= 0)
        {
            this->onMainPlayerDeath();
        }
    }
}

void GameLevelScene::onMainPlayerSkillComplate(Event *e)
{
    auto p = dynamic_cast<SkillComplateEvent *>(e);
    if (!p)
    {
        return;
    }

    //刷新一下键盘状态
    this->updateKeyState();

    //检查攻击的情况
    //如果攻击成功失败则返回
    if (p->getTargetId() < 0)
    {
        return;
    }

    auto player = this->findPlayerById(p->getTargetId());
    if (!player)
    {
        return;
    }

    bool is_critical = random(10000) < 10000 * 0.6;
    int h = is_critical ? p->getDamage() * 2 : p->getDamage();
    player->modifyHp(-h, is_critical ? IPlayer::ModifyHpType::Critical : IPlayer::ModifyHpType::Nomale);

    return;
}

void GameLevelScene::onMainPlayerDeath()
{
    m_mainRelo->death();
    auto scheduler = GameWorld::getInstance()->getScheduler();

    this->onGameOver();

    scheduler->addSchedulerTaskDelay([this, scheduler]()
                                     {

		m_gameOverWidget->setDefeated();
		m_gameOverWidget->show(); },
                                     "{68C9E12A-C121-4A1C-BF91-9E5FDA7FA59C}", 2000);
}

void GameLevelScene::onGameVictory()
{
    auto scheduler = GameWorld::getInstance()->getScheduler();

    scheduler->addSchedulerTaskDelay([this, scheduler]()
                                     {
		m_gameOverWidget->setVictory();
		m_gameOverWidget->show(); },
                                     "{68C9E12A-C121-4A1C-BF91-9E5FDA7FA59C}", 2000);
}

void GameLevelScene::onGameOver()
{
    auto scheduler = GameWorld::getInstance()->getScheduler();

    scheduler->removeSchedulerTask(MonsterUpdateState);
    scheduler->removeSchedulerPeerFrame(m_scheduleKey);
    InputEventDispatcher::getInstance()->removeListener(m_keyboardListenerId);
}

void GameLevelScene::onNextLevel()
{
    auto scheduler = GameWorld::getInstance()->getScheduler();

    scheduler->addSchedulerTaskDelay([this, scheduler]()
                                     {
		m_gameOverWidget->setNextLevel();
		m_gameOverWidget->show(); },
                                     "{68C9E12A-C121-4A1C-BF91-9E5FDA7FA53C}", 2000);
}
